package com.zhangkeyou.map.mapweb.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zhangkeyou.map.mapweb.domain.entity.Article;
import com.zhangkeyou.map.mapweb.domain.entity.LoginUser;
import com.zhangkeyou.map.mapweb.domain.entity.MyFile;
import com.zhangkeyou.map.mapweb.domain.entity.Status;
import com.zhangkeyou.map.mapweb.exception.DefinitionException;
import com.zhangkeyou.map.mapweb.mapper.FileMapper;
import com.zhangkeyou.map.mapweb.mapper.UserinfoMapper;
import com.zhangkeyou.map.mapweb.util.MyUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FileService {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileService.class);
    @Autowired
    private FileMapper fileMapper;

    @Autowired
    private UserinfoMapper userinfoMapper;

    private static String UPLOAD_FLODER = System.getProperty("user.dir")+"/upload/";
    static{
        File file = new File(UPLOAD_FLODER);
        if(!file.exists()){
            file.mkdir();
            LOGGER.info("创建了文件夹3.2"+UPLOAD_FLODER);
        }else{
            LOGGER.info("文件保存在3.2"+UPLOAD_FLODER);
        }
    }

    public String addFile(MultipartFile file, MyUtils.FileSource source, String articleId) throws IOException {
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if(Objects.isNull(loginUser))
            throw new RuntimeException("未登录");
        String userId = loginUser.getUserinfo().getId();

        String onePath = UPLOAD_FLODER+ UUID.randomUUID().toString()+"/";
        String id = UUID.randomUUID().toString();
        String fileName = file.getOriginalFilename();
        String filePath = onePath+file.getOriginalFilename();
        String resultPath = "/api/file/download2?fileId="+id+"&source="+source+"&userId="+userId;

        String path = saveFile(file,onePath);
        MyFile myFile = new MyFile();
        myFile.setSource(source);
        myFile.setId(id);
        myFile.setFileName(fileName);
        myFile.setFilePath(filePath);
        myFile.setUserinfoId(userId);
        myFile.setArticleSave(articleId);
        LOGGER.info("userId["+userId+"] save file["+file.getOriginalFilename()+"] at ["+filePath+"]");

        fileMapper.insert(myFile);
        return resultPath;
    }

    private String saveFile(MultipartFile file,String path) throws IOException {
        File folder = new File(path);
        if(!folder.exists()){
            folder.mkdir();
        }

        String filePath = path+file.getOriginalFilename();
        file.transferTo(new File(filePath));
        System.out.println(new Date()+"-->保存文件："+filePath);
        return filePath;
    }

    public List<MyFile> selectFileListWithoutPath(MyUtils.FileSource source){

        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String userId = loginUser.getUserinfo().getId();
        LambdaQueryWrapper<MyFile> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MyFile::getUserinfoId,userId);
        wrapper.eq(MyFile::getSource,source);
        List<MyFile> myFiles = fileMapper.selectFileListWithoutPath(userId,source);
        return myFiles;

    }

    public String getFilePath(String fileId, MyUtils.FileSource source,String userId) {
        MyFile myFile = new MyFile();
        myFile.setId(fileId);
        myFile.setUserinfoId(userId);
        myFile.setSource(source);
        return fileMapper.getFilePath(myFile);
    }

    public Status deleteFile(String fileId, String userId, MyUtils.FileSource source) {

        Status status=new Status();
        try{
            MyFile myFile = new MyFile();
            myFile.setId(fileId);
            myFile.setUserinfoId(userId);
            myFile.setSource(source);
            String filePath = fileMapper.getFilePath(myFile);

            QueryWrapper<MyFile> fileQueryWrapper = new QueryWrapper<>();
            fileQueryWrapper.eq("id",fileId);
            fileQueryWrapper.eq("userinfo_id",userId);
            fileQueryWrapper.eq("source",source);
            fileMapper.delete(fileQueryWrapper);

            File file = new File(filePath);
            file.delete();
            log.debug(String.format("删除文件%s，位置：%s", file.getName(),filePath));

            String[] list = file.getParentFile().list();
            if(list.length==0){
                file.getParentFile().delete();
                log.debug(String.format("删除文件夹：%s",file.getParentFile().getName()));
            }
            status.setState(200);
            status.setMsg("删除成功");
        }catch (Exception ex){
            status.setState(400);
            status.setData(ex);
            status.setMsg("删除失败");
            System.out.println(ex);
        }
        return status;
    }

    public int setArticleId(String fileId, String articleId) {
        return fileMapper.updateArticleId(fileId,articleId);
    }

    public Integer deleteFileByArticleId(Article article) {
        QueryWrapper<MyFile> fileQueryWrapper = new QueryWrapper<>();
        fileQueryWrapper.eq("article_id",article.getId());
        fileQueryWrapper.eq("source",MyUtils.FileSource.ARTICLE);
        fileQueryWrapper.eq("userinfo_id",article.getUserinfoid());
        List<MyFile> myFiles = fileMapper.selectList(fileQueryWrapper);
        myFiles.forEach(myFile -> {
            deleteFile(myFile.getId(), article.getUserinfoid(), MyUtils.FileSource.ARTICLE);
        });
        return myFiles.size();
    }

    /**
     * 查询数据库中，保存该文章的照片
     * @param articleId
     * @return
     */
    public List<String> getFileIdListByArticleId(String articleId) {
        return fileMapper.getFileIdListByArticleId(articleId,MyUtils.FileSource.ARTICLE);
    }

    public int deleteImageInNullArticle() {
        List<MyFile> fileList = fileMapper.getImageInNullArticle(MyUtils.FileSource.ARTICLE);
        log.debug(
                String.format("保存文章后，删除没有没有articleId的文件%s",
                        fileList.stream().map(file->file.getFileName()).collect(Collectors.toList()).toString()
                )
        );
        fileList.forEach(file->{
            deleteFile(file.getId(),file.getUserinfoId(),file.getSource());
        });
        return fileList.size();
    }

    public void downloadFile(HttpServletResponse response, String fileId, MyUtils.FileSource source, String userId) throws IOException {
        if(Objects.isNull(userId)){
            LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            //todo 统一下载后去掉userId的参数
            userId = loginUser.getUserinfo().getId();
        }
        String filePath = getFilePath(fileId, source ,userId);
        File file = null;
        if (filePath == null) {
            throw new DefinitionException(403,"没有找到文件");
//            return status;
        } else {
            file = new File(filePath);
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf-8");
            response.setContentLength((int) file.length());
//            "Content-Disposition, attachment;fileName="
            response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(file.getName(), "UTF-8"));
            response.addHeader("Content-Type", "application/octet-stream");


            try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));) {
                byte[] buff = new byte[1024];
                OutputStream os = response.getOutputStream();
                int i = 0;
                while ((i = bis.read(buff)) != -1) {
                    os.write(buff, 0, i);
                    os.flush();
                }
            } catch (IOException e) {
                throw e;
            }
        }

    }
}
